<!-- eslint-disable vue/no-mutating-props -->
<script setup lang="ts">
import {
  DynamicFormItem,
  DynamicFormItemSubset,
  type FormConfigModel,
  type FormConfigElement
} from '@/DynamicForm'
import { NForm, NScrollbar, useMessage, type FormInst } from 'naive-ui'
import { sendRequest } from '@/utils/api'
import { ref, watch } from 'vue'

type Data = Record<string, any>
type Vars = Record<string, any>

export interface DynamicFormComponentInst {
  formInst: FormInst | null
}

const props = withDefaults(
  defineProps<{
    data?: Data
    disabled?: boolean
    createVars?(e: FormConfigElement): Vars
    isCB?: boolean
    itemTypeCode?: string
  }>(),
  {
    data: () => ({} as Data),
    disabled: false,
    createVars: () => () => ({} as Vars),
    isCB: false
  }
)

const handleAddSubItem = (k: string) => {
  const subItems = props.data[k] || []
  subItems.push({})
  props.data[k] = subItems
}
const handleDeleteSubItem = (k: string, i: number) => {
  const subItems = props.data[k]
  if (subItems) {
    subItems.splice(i, 1)
    props.data[k] = subItems
  }
}

const message = useMessage()
const formConfigModel = ref<FormConfigModel[]>([])
const configModelLoading = ref(false)
const fetchJsonUrlLoading = ref(false)
const formInst = ref<FormInst | null>(null)

const handleDeleteDiff = () => {
  const dataKeys = Object.keys(props.data)
  const modelKeys = formConfigModel.value.reduce<string[]>(
    // @ts-ignore
    (acc, cur) => acc.concat(cur.elements.map((e) => e.formItemProps?.path)),
    []
  )
  const diffKeys = dataKeys.filter((k) => !modelKeys.includes(k))
  diffKeys.forEach((k) => delete props.data[k])
}

defineExpose({ formInst })

const handleVersionTypeChange = async () => {
  fetchJsonUrlLoading.value = true
  try {
    const [error, res] = await sendRequest({
      module: 'json',
      api: 'selectJsonUrlByCode',
      override: {
        params: {
          code: props.isCB ? props?.itemTypeCode : props.data.BMCOM003,
          cbFlag: props.isCB ? 1 : 0 //初编
        }
      }
    })
    if (error) throw error
    if (res.code !== 0) throw new Error(res.msg)
    if (!res.data) return message.warning('暂无配置！')
    handleQueryFormConfigModel(res.data)
  } catch (error) {
    if (error instanceof Error) message.error(error.message)
    console.error(error)
  } finally {
    fetchJsonUrlLoading.value = false
  }
}
if (!props.isCB) {
  watch(
    () => props.data.BMCOM003,
    () => handleVersionTypeChange(),
    { immediate: true }
  )
}

const handleQueryFormConfigModel = async (url: string) => {
  configModelLoading.value = true

  try {
    const res = await fetch(url)
    if (!res.ok) throw new Error('Network response was not ok.')
    formConfigModel.value = await res.json()
    handleDeleteDiff()

    formInst.value?.restoreValidation()
  } catch (error) {
    if (error instanceof Error) message.error(error.message)
    console.error(error)
  } finally {
    configModelLoading.value = false
  }
}

const elementStyle = (e: FormConfigModel) => {
  const style = {
    flex: '1'
  } as any
  if (e.elements.length === 1) style.gridColumn = '1 / span 2'

  return style
}

handleVersionTypeChange()
</script>

<template>
  <div class="dynamic-form">
    <NScrollbar style="max-height: 100%">
      <NForm
        ref="formInst"
        :model="data"
        label-placement="left"
        require-mark-placement="left"
        class="dynamic-form__content"
        :disabled="disabled"
        label-width="100"
      >
        <div
          v-for="(e, i) in formConfigModel"
          :key="i"
          class="form-group"
        >
          <slot
            name="title"
            :config="e"
          >
            <div
              v-if="e.title"
              class="form-group__title"
            >
              {{ e.title }}
            </div>
          </slot>

          <template v-if="e.subset">
            <DynamicFormItemSubset
              :subset="e.subset"
              :data="data"
              @add:subItem="handleAddSubItem"
              @delete:subItem="handleDeleteSubItem"
            >
              <template #default="{ value }">
                <div class="form-group__items">
                  <DynamicFormItem
                    v-for="(c, ci) in value"
                    :key="c.formItemProps?.path || ci"
                    :config="c"
                    style="flex: 1"
                    flex="1"
                    :vars="createVars(c)"
                  />
                </div>
              </template>
              <template #subItems="{ elements }">
                <div class="form-group__items">
                  <DynamicFormItem
                    v-for="(c, ci) in elements"
                    :key="c.formItemProps?.path || ci"
                    :config="c"
                    flex="1"
                    style="flex: 1"
                    :vars="createVars(c)"
                  />
                </div>
              </template>
            </DynamicFormItemSubset>
          </template>

          <div class="form-group__items">
            <template v-for="(c, ci) in e.elements">
              <slot
                name="control"
                :config="c"
              >
                <DynamicFormItem
                  flex="1"
                  :key="c.formItemProps?.path || ci"
                  :config="c"
                  :data-value="c.formItemProps?.path ? c.formItemProps.path in data : null"
                  :style="elementStyle(e)"
                  :vars="createVars(c)"
                  label-suffix="："
                />
              </slot>
            </template>
          </div>
        </div>
      </NForm>
    </NScrollbar>
  </div>
</template>

<style scoped>
:deep(.n-scrollbar-container) {
  min-height: 100%;
}
:deep(.n-scrollbar-content) {
  height: 100%;
}

.dynamic-form__content {
  height: 100%;
  background-color: #e1e1e1;
}

.form-group__title {
  font-size: 14px;
  font-weight: 600;
  color: #333333;
  margin-bottom: 1em;
}

.form-group__items {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 0 10px;
}
</style>
